home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / read_interfile.pro < prev    next >
Text File  |  1997-07-08  |  12KB  |  440 lines

  1. ; $Id: read_interfile.pro,v 1.9 1997/01/15 03:11:50 ali Exp $
  2. ;
  3. ; Copyright (c) 1993-1997, Research Systems, Inc.  All rights reserved.
  4. ;    Unauthorized reproduction prohibited.
  5. ;+
  6. ; NAME:
  7. ;    READ_INTERFILE
  8. ;
  9. ; PURPOSE:
  10. ;    Simplistic Interfile (v3.3) reader. Can only read a series
  11. ;    of images containing byte,int,long,float or double data where
  12. ;    all images have the same height and with.  Result is returned
  13. ;    in a 3-D array.
  14. ;
  15. ; CATEGORY:
  16. ;    Input/Output.
  17. ;
  18. ; CALLING SEQUENCE:
  19. ;    READ_INTERFILE, File, Data
  20. ;
  21. ; INPUTS:
  22. ;    File:    Scalar string containing the name of the Interfile
  23. ;        to read.  Note: if the Interfile has a header file and
  24. ;        a data file, this should be the name of the header
  25. ;        file (also called the administrative file).
  26. ;    
  27. ; OUTPUTS:
  28. ;    Data: A 3-D array of data as read from the file.  Assumed to be
  29. ;    a series of 2-D images.
  30. ;
  31. ; RESTRICTIONS:
  32. ;    This is a simplistic reader.  It does not get additional
  33. ;    keyword information above and beyond what is needed to read
  34. ;    in the image data.  If any problems occur reading the file,
  35. ;    READ_INTERFILE prints a message and stops.
  36. ;
  37. ;    If the data is stored in on a bigendian machine and read on
  38. ;    a littleendian machine (or vice versa) the order of bytes in
  39. ;    each pixel element may be reversed, requiring a call to
  40. ;    BYTEORDER
  41. ;
  42. ; PROCEDURE:
  43. ;    Generates keyword table and initializes it on the fly.
  44. ;    Read in administrative data.
  45. ;    Read in binary data.
  46. ;    Clean up keyword processing information.
  47. ;
  48. ; EXAMPLE:
  49. ;    READ_INTERFILE, '0_11.hdr', X
  50. ;
  51. ; MODIFICATION HISTORY:
  52. ;     Written by:    J. Goldstein, Oct 1993
  53. ;
  54. ;    12/22/93 JWG,TH        Bug fixes. Added byte swapping for short data
  55. ;-
  56.  
  57. ;
  58. ;  GetPath
  59. ;
  60. FUNCTION GetPath, File, PATH=DoPath, FILE=DoFile
  61.  
  62.     Idx    = WHERE(!Version.OS EQ [ "vms", "Win32", "MacOS" ])
  63.     Idx    = Idx[0] + 1
  64.         ;   Unix, VMS, WIN, MAC
  65.     First    = ([ '/', ']', '\', ':'])[Idx]
  66.     Second    = ([ '',  ':', ':', ''])[Idx]
  67.  
  68.     FileStart    = RSTRPOS(File, First)+1
  69.     IF FileStart EQ 0 AND Second NE '' THEN $
  70.     FileStart = RSTRPOS(File,Second)+1
  71.  
  72.     IF KEYWORD_SET(DoFile) THEN $
  73.     RETURN, STRMID(File, FileStart, 1000)
  74.     RETURN, STRMID(File,0,FileStart)
  75. END
  76.  
  77. ;
  78. ;  Inter_MakeInfo
  79. ;    Create keyword table entries.  Create hetergenous data by
  80. ;    EXECUTE'ing initialization strings and storing the results
  81. ;    in unrealized base widget UVALUE's.  This may seem confusing.
  82. ;    It probably is.
  83. ;
  84. PRO Inter_MakeInfo, Info, Filename
  85.  
  86.     ;    NB. Add hash entry for faster lookup if list gets large.
  87.     ;    E.g. FOR I=0,Info_Size-1 DO Info[i].Hash = TOTAL(BYTE(Info[i].Name))
  88.  
  89.     Entry = { IFSYM,    $
  90.     Keyword:    "",    $
  91.     Value:        0L,    $    ; Use UVALUE to hold current value
  92.     Default:    "",    $    ; EXECUTE this to create initial value
  93.     Handler:    "",    $    ; Generic keyword processor
  94.     Choices:    0L,    $    ; If limited set of choices, these
  95.     ChoiceInit:    "",    $    ; are them
  96.     IsArray:    0,    $    ; keyword requires indexing?
  97.     Proc:        ""    $    ; Special per keyword processing
  98.     }
  99.  
  100.     ;    These are the currently supported keywords.
  101.  
  102.     DefaultDataFile    = GetPath(Filename, /FILE)
  103.  
  104.     Info    = [ $
  105.     { IFSYM, "data starting block",  0L, '0L', "INT", 0L, "", 0, "" }, $
  106.     { IFSYM, "data offset in bytes", 0L, '0L', "INT", 0L, "", 0, "" }, $
  107.     { IFSYM, "data compression", 0L, $
  108.         "'none'", "STR", 0L, "'none'", 0, "" }, $
  109.     { IFSYM, "data encode", 0L, $
  110.         "'none'", "STR", 0L, "'none'", 0, "" }, $
  111.     { IFSYM, "imagedata byte order", 0L, $
  112.         "'bigendian'", "STR", 0L, $
  113.         "[ 'bigendian','littleendian' ]", 0, "" }, $
  114.     { IFSYM, "matrix size", 0L, $
  115.         '[0L,0L]', "INT", 0L, "", 1, "Inter_Fixed" }, $
  116.     { IFSYM, "name of data file", 0L, $
  117.         "'"+DefaultDataFile+"'", "STR", 0L, "", 0, "" }, $
  118.     { IFSYM, "number format", 0L, $
  119.         "'unsigned integer'", "STR", 0L, $
  120.         "[ 'signed integer','unsigned integer'," + $
  121.           "'long float', 'short float','bit' ]", 0, "" }, $
  122.     { IFSYM, "number of bytes per pixel", 0L, '0L',"INT",0L, "", 0, "" }, $
  123.     { IFSYM, "total number of images", 0L, '0L', "INT", 0L, "", 0, "" } $
  124.     ]
  125.  
  126.     ;    Run through keywords and create initial values
  127.     ;    and choice values if keyword has a limited set of choices
  128.  
  129.     FOR I=0,N_ELEMENTS(Info)-1 DO BEGIN
  130.  
  131.     ;    Create value
  132.  
  133.     Info[I].Value    = WIDGET_BASE()
  134.     Value        = 0
  135.     Result        = EXECUTE("Value = " + Info[I].Default)
  136.     IF Result NE 1 THEN MESSAGE, "Cannot initialize Info structure"
  137.     WIDGET_CONTROL, Info[I].Value, SET_UVALUE=Value
  138.  
  139.     ;    Create choices if they exist
  140.  
  141.     IF Info[I].ChoiceInit NE "" THEN BEGIN
  142.         Info[I].Choices    = WIDGET_BASE()
  143.         Value        = 0
  144.         Result        = EXECUTE("Value = " + Info[I].ChoiceInit)
  145.         IF Result NE 1 THEN MESSAGE, "Cannot initialize Info structure"
  146.         WIDGET_CONTROL, Info[I].Choices, SET_UVALUE=Value
  147.     ENDIF
  148.  
  149.     ENDFOR
  150. END
  151.  
  152. ;
  153. ;  Inter_INT
  154. ;    General integer keyword processing routine
  155. ;
  156. PRO Inter_INT, KwdInfo, Value, Arr
  157.  
  158.     Value    = LONG(Value)
  159.  
  160.     ;    limited # of chioces?  See if user has chosen a valid chioce
  161.  
  162.     IF KwdInfo.Choices NE 0 THEN BEGIN
  163.     WIDGET_CONTROL, KwdInfo.Choices, GET_UVALUE=Choices
  164.     Dummy    = WHERE(Value EQ Choices, Count)
  165.     IF Count NE 1 THEN $
  166.         MESSAGE, 'Illegal choice of values for ' + KwdInfo.Keyword
  167.     ENDIF
  168.  
  169.     IF KwdInfo.Proc THEN BEGIN    ;    Special keyword routine?
  170.  
  171.     CALL_PROCEDURE, KwdInfo.Proc, KwdInfo, Value, Arr
  172.  
  173.     ENDIF ELSE BEGIN        ;    General processing
  174.     IF KwdInfo.IsArray THEN BEGIN
  175.         WIDGET_CONTROL, KwdInfo.Value, GET_UVALUE=Vals
  176.         Vals[Arr-1]    = Value
  177.     ENDIF ELSE BEGIN
  178.         Vals    = Value
  179.     ENDELSE
  180.  
  181.         WIDGET_CONTROL, KwdInfo.Value, SET_UVALUE=Vals
  182.     ENDELSE
  183. END
  184.  
  185.  
  186. ;
  187. ;  Inter_STR
  188. ;    General string keyword processing routine
  189. ;
  190. PRO Inter_STR, KwdInfo, Value, Arr
  191.  
  192.     ;    Hack. I've seen people use Keyword:=
  193.     ;    Perhaps I should just add '' to the list of valid values.
  194.     IF Value EQ '' THEN VALUE = 'none'
  195.  
  196.     IF KwdInfo.Choices NE 0 THEN BEGIN
  197.     WIDGET_CONTROL, KwdInfo.Choices, GET_UVALUE=Choices
  198.     Value    = STRLOWCASE(Value)
  199.     Dummy    = WHERE(Value EQ Choices, Count)
  200.     IF Count NE 1 THEN $
  201.         MESSAGE, 'Illegal choice of values for ' + KwdInfo.Keyword
  202.     ENDIF
  203.  
  204.     IF KwdInfo.Proc THEN BEGIN
  205.  
  206.     CALL_PROCEDURE, KwdInfo.Proc, KwdInfo, Value, Arr
  207.  
  208.     ENDIF ELSE BEGIN
  209.     IF KwdInfo.IsArray THEN BEGIN
  210.         WIDGET_CONTROL, KwdInfo.Value, GET_UVALUE=Vals
  211.         Vals[Arr-1]    = Value
  212.     ENDIF ELSE BEGIN
  213.         Vals        = Value
  214.     ENDELSE
  215.  
  216.         WIDGET_CONTROL, KwdInfo.Value, SET_UVALUE=Vals
  217.     ENDELSE
  218. END
  219.  
  220.  
  221. ;
  222. ;  Inter_Fixed
  223. ;    Routine to tell user that this is a simple reader.
  224. ;    If the size of a keyword element has been changed
  225. ;    and it wasn't 0 before, tell user we give up.
  226. ;
  227. ;    This is for :matrix size: because we don't handle images
  228. ;    of different sizes.
  229. ;
  230. PRO Inter_Fixed, KwdInfo, Value, Arr
  231.  
  232.     WIDGET_CONTROL, KwdInfo.Value, GET_UVALUE=Vals
  233.     IF KwdInfo.IsArray THEN Val = Vals[Arr-1] $
  234.     ELSE Val = Vals
  235.  
  236.     IF Val EQ 0 THEN BEGIN
  237.  
  238.     IF KwdInfo.IsArray THEN Vals[Arr-1] = Value $
  239.     ELSE Vals = Value
  240.     WIDGET_CONTROL, KwdInfo.Value, SET_UVALUE=Vals
  241.  
  242.     ENDIF ELSE IF Value NE Val THEN BEGIN
  243.  
  244.     MESSAGE, "Support of Interfiles where " + KwdInfo.Keyword + $
  245.         " changes is not currently supported"
  246.  
  247.     ENDIF
  248. END
  249.  
  250.  
  251. ;
  252. ;  Inter_ReadHdr
  253. ;    Wade through administrative data looking for the keywords
  254. ;    we understand.  Quietly ignore any keywords not in the Info
  255. ;    list. This should provide enough information to either
  256. ;    read the data or realize we can't read the data.
  257. ;
  258. ;    N.B. STRMID(Str,Start, 255) will return the remainder of a
  259. ;    string as long as that string is less than 255 characters long --
  260. ;    which the Interfile 3.3 spec guarantees
  261. ;
  262. PRO Inter_ReadHdr, Unit, Info
  263.  
  264.     ;    Parse lines until
  265.     Line    = ""
  266.     WHILE NOT EOF(Unit) DO BEGIN
  267.     READF, Unit, Line            ; Read in line of text
  268.  
  269.     ;    Remove leading/trailing whitespace (blech)
  270.     BLine        = BYTE(Line)
  271.     Idx        = WHERE(Bline EQ 13b OR Bline EQ 10b, Count)
  272.     IF Count GT 0 THEN Bline[Idx] = 32b
  273.     Line        = STRTRIM(BLine,2)
  274.  
  275.     IF Line EQ '' THEN GOTO, Continue    ; ignore blank lines
  276.  
  277.     FirstChar    = STRMID(Line,0,1)    ; ';' is comment character
  278.     IF FirstChar EQ ";" THEN GOTO, Continue
  279.  
  280.     ;    Find full Keyword
  281.     KeyStart    = FirstChar EQ "!"
  282.     KeyEnd        = STRPOS(Line, ":=")
  283.     Kwd        = STRMID(Line, KeyStart,KeyEnd-KeyStart)
  284.  
  285.     ;    Look for array index
  286.     ArrStart    = STRPOS(Kwd, "[")
  287.     IF ArrStart NE -1 THEN BEGIN
  288.         Arr    = FIX( STRMID(Kwd,ArrStart+1, 255))
  289.         Kwd    = STRMID(Kwd, 0, ArrStart)
  290.     ENDIF ELSE BEGIN
  291.         Arr    = 0
  292.     ENDELSE
  293.  
  294.     Kwd        = STRLOWCASE(STRTRIM(Kwd,2))
  295.  
  296.     ;    Look for value
  297.     Value        = STRMID(Line,KeyEnd+2,255)
  298.     ValEnd        = STRPOS(Value, ";")
  299.     IF ValEnd NE -1 THEN Value = STRMID(Value,0,ValEnd-1)
  300.     Value        = STRTRIM(Value,2)
  301.  
  302.     ;    We now have keyword, array index and value
  303.  
  304.     ;    Special case for the 'End of Interfile' keyword
  305.     ;    It does not set a value like the other keywords.
  306.     IF Kwd EQ "end of interfile" THEN RETURN
  307.  
  308.     Idx    = WHERE(Kwd EQ Info.Keyword, Count)
  309.     IF Count EQ 0 THEN GOTO, Continue
  310.     KwdInfo    = Info[Idx]
  311.  
  312.     ;    Either we have an array with no subscripting which requires
  313.     ;    it or we have an array with a subscript that can't have one
  314.  
  315.     IF (Arr NE 0) XOR (KwdInfo.IsArray NE 0) THEN BEGIN
  316.         IF Arr NE 0 THEN $
  317.         MESSAGE, 'Keyword :'+KwdInfo.Keyword +': cannot have subscript'
  318.         MESSAGE, 'Keyword :' + KwdInfo.Keyword + ': must have subscript'
  319.     ENDIF
  320.  
  321.     CALL_PROCEDURE, "Inter_" + KwdInfo.Handler, $
  322.         KwdInfo, Value, Arr
  323.     Continue:
  324.     ENDWHILE
  325. END
  326.  
  327. ;
  328. ;  GetIFSYM
  329. ;    Thin UI to cover keyword finding mechanism.
  330. ;    If hash is implemented it goes here
  331. ;
  332. FUNCTION GetIFSYM, Name, Info, INDEX=Idx
  333.  
  334.     ; Hash    = FIX(TOTAL(BYTE(Name)))
  335.     ; Idxs    = WHERE(Info.Hash EQ Hash, Count)
  336.     ; IF Count eq 0 then <Error>
  337.     ; Idx    = WHERE(Name EQ Info[Idxs].Keyword, Count)
  338.  
  339.     Idx    = WHERE(Name EQ Info.Keyword, Count)
  340.     IF Count NE 1 THEN $
  341.         MESSAGE, "Unknown/unsupported keyword '" + Name + "'"
  342.     WIDGET_CONTROL, Info[Idx].Value, GET_UVALUE=Value
  343.     RETURN, Value
  344. END
  345.  
  346.  
  347. ;
  348. ;  Inter_ReadData
  349. ;    At this point we have all of the information to read the
  350. ;    data: File, Offset, Amount and Type.
  351. ;
  352. PRO Inter_ReadData, Info, Data, Path
  353.  
  354.     ;    Byte/Block offset
  355.     Offset    = GetIFSYM("data offset in bytes", Info)
  356.     IF Offset EQ 0L THEN BEGIN
  357.     Offset    = GetIFSYM("data starting block", Info)
  358.     Offset    = Offset * 2048
  359.     ENDIF
  360.  
  361.     FileName    = Path + GetIFSYM("name of data file", Info)
  362.     Sz        = LONARR(6)
  363.     Sz[0]    = 3    ; 3 dimensions
  364.     Sz[1:2]    = GetIFSYM("matrix size", Info)
  365.     Sz[3]    = GetIFSYM("total number of images", Info)
  366.  
  367.     ;    Now the tricky one. Data Type:
  368.     ;    Use elements size and number format.
  369.     ;    I hope we blow up if things are wierd (3 bytes/pixel
  370.     ;    or other unsupported conditions)
  371.     
  372.     ElemSize    = GetIFSYM("number of bytes per pixel", Info)
  373.     InterType    = GetIFSYM("number format", Info)
  374.  
  375.     CASE InterType OF
  376.  
  377.     'bit':        MESSAGE, "Unsupported Data Type."
  378.  
  379.     'unsigned integer':    GOTO, IntData
  380.     'signed integer':    BEGIN
  381.     IntData:
  382.     Type    = [ 1, 2, 0, 3 ]    ; byte/int/error/long
  383.     Type    = Type[ElemSize-1]
  384.     END
  385.  
  386.     'short float':    Type    = 4
  387.     'long float':    Type    = 5
  388.  
  389.     ENDCASE
  390.  
  391.     Sz[4]    = Type
  392.  
  393.     OPENR, Unit, FileName, /GET_LUN
  394.     Data = MAKE_ARRAY(SIZE=Sz, /NOZERO)
  395.     POINT_LUN, Unit, Offset
  396.     READU, Unit, Data
  397.     FREE_LUN, Unit
  398.  
  399.     ;    There are other combinations that require
  400.     ;    byteswapping but this is what was found
  401.     ;    so far.
  402.  
  403.     Endian    = GetIFSYM("imagedata byte order", Info)
  404.  
  405.     ;    Short int data. If we are on some machine where the
  406.     ;    endianness is the reverse of that in the file...
  407.  
  408.     IF Type EQ 2 THEN BEGIN
  409.  
  410.     ;    Determine the endianness of the machine
  411.  
  412.     LocalEndian    = (BYTE(1, 0, 1))[0]
  413.  
  414.     ;    If the endianness of the machine doesn't
  415.     ;    match the endianness of the file then swap
  416.  
  417.     IF (Endian EQ 'littleendian' AND LocalEndian EQ 0) OR $
  418.        (Endian EQ 'bigendian' AND LocalEndian EQ 1) THEN BEGIN
  419.  
  420.         BYTEORDER, Data, /SSWAP
  421.     ENDIF
  422.     ENDIF
  423. END
  424.  
  425.  
  426. PRO Read_Interfile, Filename, Data
  427.  
  428.     OPENR, Unit, Filename, /GET_LUN
  429.     Inter_MakeInfo, Info, Filename
  430.     Inter_ReadHdr, Unit, Info
  431.     FREE_LUN, Unit
  432.     Inter_ReadData, Info, Data, GetPath(Filename, /PATH)
  433.  
  434.     ; Release Information structure information
  435.     FOR I=0,N_ELEMENTS(Info)-1 DO BEGIN
  436.     IF Info[I].Value NE 0L THEN WIDGET_CONTROL, Info[I].Value, /DESTROY
  437.     IF Info[I].Choices NE 0L THEN WIDGET_CONTROL, Info[I].Choices, /DESTROY
  438.     ENDFOR
  439. END
  440.